package helper.scxml.scxml2.zone.t1

import helper.base.CloneHelper.Expand.CloneableList.cloneList
import helper.base.CloneHelper.Expand.StringList.cloneList
import helper.base.ConstraintHelper.W1N1N2Constraint
import helper.base.StateHelper.EventChoice
import helper.base.StateHelper.Graph
import helper.base.StateHelper.Path
import helper.base.StateHelper.State
import helper.base.StateHelper.StateEventPLHM
import helper.base.StateHelper.StateEventTransitionLHM
import helper.base.StateHelper.Transition

object ZoneStateHelper {
    class ZoneState(
        //内部具体结构可以按照实际具体例子固定
        val locations: ArrayList<String>,
        val cons: List<W1N1N2Constraint>,
        var reward: Double = 0.0,
        name: String = "",
    ) : State(
    ) {
        companion object {
            fun getL1ZoneState(
                location: String,
                cons: ArrayList<W1N1N2Constraint>,
                reward: Double = 0.0,
            ): ZoneState {
                return ZoneState(
                    arrayListOf(location),
                    cons,
                    reward,
                )
            }

            fun getL1C1ZoneState(
                location: String,
                c1: W1N1N2Constraint,
                reward: Double = 0.0,
            ): ZoneState {
                return getL1ZoneState(
                    location,
                    arrayListOf(c1),
                    reward,
                )
            }

            fun getL1C2ZoneState(
                location: String,
                c1: W1N1N2Constraint,
                c2: W1N1N2Constraint,
                reward: Double = 0.0,
            ): ZoneState {
                return getL1ZoneState(
                    location,
                    arrayListOf(c1, c2),
                    reward,
                )
            }
        }

        override fun clone(): ZoneState {
            return ZoneState(
                locations.cloneList(),
                cons.cloneList(),
                reward,
                name,
            )
        }

        override fun toString(): String {
            val sb = StringBuilder()
            sb.append("(${locations.joinToString(",")})")
            sb.append(",")
            sb.append(cons.joinToString(","))
            return sb.toString()
        }

        fun toString2(): String {
            val sb = StringBuilder()
            sb.append("${name},")
            sb.append("(${locations.joinToString(",")})")
            sb.append(",")
            sb.append("(${cons.joinToString(" and ")})")
            return sb.toString()
        }
    }

    class ZoneTransition(
        start: ZoneState,
        eventChoice: EventChoice,
        end: ZoneState,
    ) : Transition<ZoneState, EventChoice>(
        start,
        eventChoice,
        end,
    ) {
        companion object {
            fun getZoneTransition(
                start: ZoneState,
                eventChoice: EventChoice,
                end: ZoneState,
            ): ZoneTransition {
                return ZoneTransition(
                    start,
                    eventChoice,
                    end,
                )
            }

            fun getZoneTransition(
                start: ZoneState,
                event: String,
                end: ZoneState,
            ): ZoneTransition {
                return ZoneTransition(
                    start,
                    EventChoice.makeEventChoice(event),
                    end,
                )
            }

            fun getAutoEventZoneTransition(
                start: ZoneState,
                end: ZoneState,
            ): ZoneTransition {
                return getZoneTransition(
                    start,
                    "${start.name}${end.name}",
                    end,
                )
            }
        }

        override fun clone(): ZoneTransition {
            return ZoneTransition(
                start.clone(),
                eventChoice.clone(),
                end.clone(),
            )
        }
    }

    fun StateEventTransitionLHM<ZoneState, EventChoice, ZoneTransition>.touchPrintlnType2(
    ): String {
        val sb = StringBuilder()
        this.touch { a1: ZoneState, a2: EventChoice, a3: ZoneTransition ->
            sb.append("-".repeat(40))
            sb.append("\n")
            sb.append("[${a1.toString2()}]\n")
            sb.append("[${a2.getChosenEvent()}]\n")
            sb.append("[${a3.end.toString2()}]\n")
        }
        return sb.toString()
    }

    fun StateEventPLHM<ZoneState, EventChoice>.touchPrintlnType2(
    ): String {
        val sb = StringBuilder()
        this.touch { a1, a2, a3 ->
            sb.append("[${a1.name}][${a2.getChosenEvent()}][${a3}]\n")
        }
        return sb.toString()
    }

    class ZonePath(
        pReward: Double = 1.0,
    ) : Path<ZoneTransition>(
        pReward,
    ) {
        override fun clone(): ZonePath {
            val newPath = ZonePath(this.pReward)
            this.map {
                newPath.add(it.clone())
            }
            return newPath
        }

        override fun toString(): String {
            val sb = StringBuilder()
            sb.append("ZonePath(")
            this.map {
                sb.append("(${it.start.name},${it.chosenEvent},${it.end.name})")
                sb.append(",")
            }
            sb.append("pReward=${pReward}")
            sb.append(")")
            return sb.toString()
        }
    }

    class ZoneGraph(
        start: ZoneState,
        ts: ArrayList<ZoneTransition>,
        finalStates: LinkedHashSet<ZoneState> = LinkedHashSet(),
    ) : Graph<ZoneState, EventChoice, ZoneTransition>(
        start,
        ts,
        finalStates,
    ) {
        fun dfsTouchType11(
            nowZT: ZoneTransition? = null,
            tabSize: Int = 0,
            visited: LinkedHashSet<ZoneTransition> = LinkedHashSet(),
            sb: StringBuilder = StringBuilder(),
        ): String {
            val isNowZTNull = nowZT == null
            if (isNowZTNull) {
                sb.append("[${start.toString2()}]\n")
            } else {
                nowZT!!.let {
                    sb.append("${"\t".repeat(tabSize)}[${it.chosenEvent}][${it.end.toString2()}]\n")
                }
            }
            val nowState: ZoneState = if (isNowZTNull) {
                start
            } else {
                nowZT!!.end
            }
            if (!isNowZTNull) {
                visited.add(nowZT!!)
            }
            stateEventTLHM[nowState]?.map { (_, a3) ->
                if (visited.contains(a3)) return@map
                dfsTouchType11(
                    a3,
                    tabSize + 1,
                    visited,
                    sb,
                )
            }
            return sb.toString()
        }

        fun dfsTouchType2(
            nowZT: ZoneTransition? = null,
            visited: LinkedHashSet<ZoneTransition> = LinkedHashSet(),
            nowPath: ZonePath = ZonePath(),
            pathList: ArrayList<ZonePath> = ArrayList(),
        ) {
            val isNowZTNull = nowZT == null
            if (!isNowZTNull) {
                nowZT!!
                val totalP = this.stateEventPLHM[nowZT.start]!!.values.sum()
                val nowP = this.stateEventPLHM[nowZT.start]!![nowZT.eventChoice]!!
                nowPath.add(nowZT, nowP / totalP)
            }
            val nowState: ZoneState = if (isNowZTNull) {
                start
            } else {
                nowZT!!.end
            }
            val isEnd = this.finalStates.contains(nowState)
            if (isEnd) {
                nowPath.pReward *= nowState.reward
                pathList.add(nowPath)
                return
            }
            if (!isNowZTNull) {
                visited.add(nowZT!!)
            }
            stateEventTLHM[nowState]?.map { (_, a3) ->
                if (visited.contains(a3)) return@map
                val newPath = nowPath.clone()
                dfsTouchType2(
                    a3,
                    visited,
                    newPath,
                    pathList,
                )
            }
        }
    }
}